/*
 * @Author: KingOfLoach:469184621@qq.com
 * @Date: 2024-10-29 03:35:20
 * @LastEditors: 泥鳅王 469184621@qq.com
 * @LastEditTime: 2025-01-29 10:41:10
 * @FilePath: /LoachLogger/include/loach_logger.hpp
 * @Description: 
 * 
 * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. 
 */
#ifndef LOACH_LOGGER_HPP__
#define LOACH_LOGGER_HPP__

#include "fstream"
#include "string"
#include "vector"
#include "map"
#include "iostream"

#include "time.h"

#include "loach_tools.hpp"


// 实现文件的打开关闭功能（追加方式打开）； 
// TODO:此处实现有待于斟酌:
#define FILE_OC(func) do{\
if(!this->file_path.empty())this->fs.open(this->file_path,std::ios::app);\
func;\
if(!this->file_path.empty())fs.close();\
}while(0)


/**************************************
 * @description: logger函数计时宏定义接口
 * @note:: 
 * @param {LoachLogger} 实例化对象指针
 * @param {func}        待运行函数
 * @return {void}
 ***************************************/
#define LoggerTimer(logger_obj,func)do{\
logger_obj->FuncTimer(std::string(#func),__FUNC_TIMER__(func));\
}while(0)


/***********************************************************
***********************************************************
***********       LoachLogger 对象声明       ***************
***********************************************************
************************************************************/
class LoachLogger{
private:
    static LoachLogger * logger;    ///> 静态logger实例

public:

    /*************************************
     * @description: 获取全局唯一logger对象
     * @return {LoachLogger}
    *************************************/    
    static LoachLogger* GetLogger(){ 
        if (!logger) 
            logger = new LoachLogger(); 
        return logger; 
    }

    
    /**************************************
     * @description: 设置要写入的 .log 文件的地址
     * @note: 同时检查 log 文件所在的文件夹是否存在，不存在则创建
     * @param {string} path_in
    **************************************/
    void SetFilePath(std::string path_in);


    /**************************************
     * @description: 输出 Debug 信息
     * @param {string} input
     * @return {*}
     ***************************************/
    void Debug(std::string input);
    
    void Warning(std::string input);

    void Error(std::string input);

    void FuncTimer(std::string func_name,float t){
        this->__Print__("FUNC_TIME:: " + func_name,std::to_string(t) + " s");
    }

private:
    std::string  file_path = "";    ///> 输出LOG文件地址
    std::fstream fs;                ///> 文件流对象
    std::map<std::string ,std::string> font_color_prefixs;   ///> 输出字体颜色前缀 
    std::map<std::string ,std::string> font_color_suffixs;   ///> 输出字体颜色后缀
    
    LoachLogger(const LoachLogger&)=delete;
    LoachLogger operator=(const LoachLogger&)   =delete;

    /*****************************************************
     * @description: 构造函数  
     * @note: 构造对外部隐藏  
    *****************************************************/
    LoachLogger(){this->__InitFontClr__();}


    void __InitFontClr__();

    /*******************************************************
     * @description: 将前时间以string形式返回
     * @note: 目前只支持到秒，TODO下一步需要支持到毫秒
     * @return {std::string}
     ******************************************************/
    std::string __GetTime__();

    /*****************************************************
     * @description: 输出信息
     * @param {string} titel : "DEBUG" "INFO" ... MESSAIGE
     * @param {string} message : 要打印的信息
     * @return {*}
     ******************************************************/
    template<class T>
    void  __PrintBase__(std::string titel,std::string message,T &out_stream);
    
    /*******************************************************
     * @description: 输出信息到输出流中
     * @param {string} titel
     * @param {string} message
     * @return {*}
     ******************************************************/
    void __Print__(std::string titel,std::string message);
};


/***********************************************
    @brief : logger 对象实现 - 外部接口
***********************************************/
void LoachLogger::SetFilePath(std::string path_in){
    this->file_path = path_in;
    std::string file_dir = loach_tools::GetFileFolderPath(path_in);
    loach_tools::CheckFolder(file_dir);
}

void LoachLogger::Debug(std::string input){this->__Print__("Debug",input);}

void LoachLogger::Warning(std::string input){this->__Print__("Warning",input);}

void LoachLogger::Error(std::string input){this->__Print__("Error",input);}

/***********************************************
    @brief : logger 对象实现 - 私有接口
***********************************************/

LoachLogger* LoachLogger::logger = nullptr;  // 初始化静态变量

std::string LoachLogger::__GetTime__(){
    std::string res = "";
    // 获取时间戳
    time_t t;
    struct tm *lt;
    time(&t);
    lt  = localtime(&t);
    // 时间戳转std::string
    {
        res +=std::to_string(lt->tm_year+1900);
        res += "-";
        res +=std::to_string(lt->tm_mon);
        res += "-";
        res +=std::to_string(lt->tm_mday);
        res += " ";

        res +=std::to_string(lt->tm_hour);
        res += ":";

        res +=std::to_string(lt->tm_min);
        res += ":";

        res +=std::to_string(lt->tm_sec);
        res += ":";

        res +=std::to_string(clock());
        //res +=std::to_string(clock()/CLOCKS_PER_SEC);
        res += "::";
    }
    return res;
};

template<class T>
void LoachLogger::__PrintBase__(std::string titel,std::string message,T &out_stream){
    // print to cmd or filestream
    std::string pr="",sf="";  // 字体颜色前后缀
    if(&out_stream == &std::cout){
        pr=this->font_color_prefixs[titel];
        sf=this->font_color_suffixs[titel];
    }   

    out_stream
    <<pr
    <<this->__GetTime__()
    <<"["<<titel<<"] - "
    <<message
    <<sf
    <<std::endl;
};

void LoachLogger::__Print__(std::string titel,std::string message){
    this->__PrintBase__(titel,message,std::cout);
    if(this->file_path != ""){
        FILE_OC(this->__PrintBase__(titel,message,this->fs));
    }
}

void LoachLogger::__InitFontClr__(){
        #ifdef WIN32
            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("","")); /// None
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("","")); /// None

            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("Debug","")); /// Debug
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("Debug","")); /// Debug

            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("Warning","\033[5;33m"));   /// Warning
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("Warning","\033[0m"));      /// Warning

            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("Error","\033[1;31m"));     /// Error
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("Error","\033[0m"));        /// Error
        #else
            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("","")); /// None
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("","")); /// None

            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("Debug","")); /// Debug
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("Debug","")); /// Debug

            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("Warning","")); /// Warning
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("Warning","")); /// Warning

            this->font_color_prefixs.insert(std::pair<std::string ,std::string>("Error","")); /// Error
            this->font_color_suffixs.insert(std::pair<std::string ,std::string>("Error","")); /// Error
        #endif
    }

#endif